package com.partsoft.dits.utils;

import java.io.IOException;
import java.io.InputStream;

import org.dom4j.Document;
import org.dom4j.Namespace;
import org.dom4j.io.SAXReader;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

public class Dom4jUtils {

	/**
	 * 创建一个校验用的XSD读取器
	 * @param xsdInputStream xsd输入字节流
	 * @param readEncoding 读取编码
	 * @return {@link SAXReader}
	 */
	public static SAXReader createSAXReader(InputStream xsdInputStream, String readEncoding) throws RuntimeException {
		Assert.notNull(xsdInputStream);
		readEncoding  = StringUtils.hasText(readEncoding) ? readEncoding : "utf-8";
		
		SAXReader reader = new SAXReader(true);
		reader.setEncoding(readEncoding);
		
		reader.setEntityResolver(new XSDValidateEntityResolver(xsdInputStream));
		try {
	        reader.setFeature("http://xml.org/sax/features/validation", true);  
	        reader.setFeature("http://apache.org/xml/features/validation/schema", true);
	        reader.setFeature("http://xml.org/sax/features/namespace-prefixes", true);
	        reader.setFeature("http://apache.org/xml/features/validation/schema-full-checking", true);
		} catch (SAXException e) {
			throw new IllegalStateException(e.getMessage(), e);
		}
		return reader;
	}
	
	public static SAXReader createSAXReader() {
		SAXReader reader = new SAXReader();
		reader.setEncoding("utf-8");
		return reader;
	}
	
	/**
	 * 使用名字空间前缀转换xpath
	 * @param xpath
	 * @param namespacePrefix
	 * @return
	 */
	public static String transformXpath(String xpath, String namespacePrefix) {
		if (!StringUtils.hasText(namespacePrefix)) return xpath;
		String[] strs = xpath.split("/");
		StringBuffer tempPath = new StringBuffer();
		for(String str : strs) {
			if (".".equals(str) || "..".equals(str)) {
				tempPath.append(str);
			} else if (!"".equals(str)) {
				tempPath.append(namespacePrefix).append(":").append(str);
			}
			tempPath.append("/");
		}
		tempPath.deleteCharAt(tempPath.length() - 1);
		return tempPath.toString();
	}

	/**
	 * 获取缺省的名字空间前缀
	 * @param doc Dom4j的{@link Document}句柄
	 * @param namespaceURI 
	 * @param defaultPrefix 如果无缺省的空间前缀，则使用此参数（如果此参数不填写则使用"dits"）
	 * @return 名字空间前缀
	 */
	public static String resolveDefaultNamespacePrefix(Document doc, String namespaceURI, String defaultPrefix) {
		Assert.notNull(doc);
		Assert.hasText(namespaceURI);
		String prefixName = "";
		if (!StringUtils.hasText(doc.getRootElement().getNamespaceURI())) {
			return prefixName;
		}

		namespaceURI = doc.getRootElement().getNamespaceURI();
		Namespace dNs = doc.getRootElement().getNamespaceForURI(namespaceURI);
		if (dNs == null) {
			//找不到，就用缺省的。
			namespaceURI = doc.getRootElement().getNamespaceURI();
		} else {
			if (dNs.getPrefix().length() > 0) {
				prefixName = dNs.getPrefix();
			}
		}
		if (prefixName.length() == 0) {
			prefixName = StringUtils.hasText(defaultPrefix) ? defaultPrefix.trim() : "dits" ;
			int i = 1;
			while(doc.getRootElement().getNamespaceForPrefix(prefixName) != null) {
				prefixName = prefixName + i;
			}
			doc.getRootElement().addNamespace(prefixName, namespaceURI);
		}
		
		return prefixName;
	}
	
	public static String encodeXML(String source) {
		Assert.notNull(source);
		String retstr = source;
		retstr = StringUtils.replace(retstr, "<", "&lt;");
		retstr = StringUtils.replace(retstr, ">", "&gt;");
		retstr = StringUtils.replace(retstr, "&", "&amp;");
		retstr = StringUtils.replace(retstr, "'", "&apos;");
		retstr = StringUtils.replace(retstr, "\"", "&quot;");
		retstr = StringUtils.replace(retstr, " ","&#x20;");
		retstr = StringUtils.replace(retstr, "\t","&#x09;");
		retstr = StringUtils.replace(retstr, "\r","(&#x0D;");
		retstr = StringUtils.replace(retstr, "\n","&#x0A;");
		return retstr;
	}
	
	public static String decodeXML(String source) {
		Assert.notNull(source);
		String retstr = source;
		retstr = StringUtils.replace(retstr, "&lt;", "<");
		retstr = StringUtils.replace(retstr, "&gt;", ">");
		retstr = StringUtils.replace(retstr, "&amp;", "&");
		retstr = StringUtils.replace(retstr, "&apos;", "'");
		retstr = StringUtils.replace(retstr, "&quot;", "\"");
		retstr = StringUtils.replace(retstr,"&#x20;", " ");
		retstr = StringUtils.replace(retstr,"&#x09;", "\t");
		retstr = StringUtils.replace(retstr,"(&#x0D;", "\r");
		retstr = StringUtils.replace(retstr,"&#x0A;", "\n");
		return retstr;
	}
	
	public static void validateSpringID(String sourceID) {
		Assert.isTrue((sourceID.charAt(0) >= 'a' && sourceID.charAt(0) <= 'z') ||
				(sourceID.charAt(0) >='A' && sourceID.charAt(0) <='Z') ||
				(sourceID.charAt(0) == '_'), "必须符合ID规范(首字母必须是字母或者_。");
		
		for (int i = 1; i < sourceID.length(); i++) {
			char schar = sourceID.charAt(i);
			if ((schar >= 'a' && schar <= 'z') || 
					(schar >= 'A' && schar <= 'Z') || 
					(schar >= '0' && schar <= '9') || 
					schar == '-' || schar == '_' || schar == '.' ||
					schar == '~')
				continue;
			throw new IllegalArgumentException("ID不能包含字符\""+schar + "\"。" );
		}
	}
	
	protected static class XSDValidateEntityResolver implements EntityResolver {

		private final InputStream xsdStream;
		
		public XSDValidateEntityResolver(InputStream xsdStream) {
			this.xsdStream = xsdStream;
		}

		public InputSource resolveEntity(String s, String s1)
				throws SAXException, IOException {
			return new InputSource(xsdStream);
		}
	}
	
}
